package com.easyjava.builder;

import com.easyjava.bean.Constants;
import com.easyjava.bean.FieldInfo;
import com.easyjava.bean.TableInfo;
import com.easyjava.utils.DateUtils;
import com.easyjava.utils.MyStringUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * @Author: 小闹心
 * @Description: 创建PO对象
 * @DateTime: 2024/11/16 15:13
 **/
public class BuildPo {
    private static final Logger logger = LoggerFactory.getLogger(BuildPo.class);
    public static void execute(TableInfo tableInfo){
        File folder = new File(Constants.PATH_PO);
        if(!folder.exists()){
            folder.mkdirs();
        }
        File file = new File(folder, tableInfo.getBeanName() + ".java");
        OutputStream out = null;
        OutputStreamWriter outWriter = null;
        BufferedWriter bw = null;
        try{
            out = new FileOutputStream(file);
            outWriter = new OutputStreamWriter(out, StandardCharsets.UTF_8);
            bw = new BufferedWriter(outWriter);
            bw.write("package " + Constants.PACKAGE_PO + ";");
            bw.newLine();
            bw.newLine();
            List<FieldInfo> fieldEnumList = tableInfo.getFieldEnumList();
            for(FieldInfo fieldInfo : fieldEnumList){
                bw.write("import " + Constants.PACKAGE_ENUMS + "." + MyStringUtils.upperCaseFirstLetter(fieldInfo.getPropertyName() + "Enum;"));
                bw.newLine();
            }
            if(Constants.KNIFE4J_ENABLE){
                bw.write("import io.swagger.v3.oas.annotations.media.Schema;");
                bw.newLine();
            }
            boolean haveIgnoreBean = false;
            for(FieldInfo fieldInfo : tableInfo.getFieldList()){
                if(ArrayUtils.contains(Constants.IGNORE_BEAN_TOJSON_FIELDS,MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()))){
                    haveIgnoreBean = true;
                    break;
                }
            }
            if(haveIgnoreBean){
                bw.write(Constants.IGNORE_BEAN_TOJSON_CLASS);
                bw.newLine();
            }
            if(tableInfo.getHaveDate() || tableInfo.getHaveDateTime()){
                bw.write(Constants.BEAN_DATE_FORMAT_CLASS);
                bw.newLine();
                bw.write(Constants.BEAN_DATE_PARSE_CLASS);
                bw.newLine();
                bw.newLine();
                bw.write("import java.util.Date;");
                bw.newLine();
                bw.write("import " + Constants.PACKAGE_UTILS + ".DateUtils;");
                bw.newLine();
                bw.write("import " + Constants.PACKAGE_ENUMS + ".DateTimePatternEnum;");
                bw.newLine();
            }
            if(tableInfo.getHaveBigDecimal()){
                bw.write("import java.math.BigDecimal;");
                bw.newLine();
            }
            bw.write("import java.io.Serializable;");
            bw.newLine();
            bw.newLine();
            // 生成类注释
            BuildComment.createClassComment(bw,tableInfo.getComment());
            bw.write("public class " + tableInfo.getBeanName() + " implements Serializable {");
            bw.newLine();

            // 生成属性
            for(FieldInfo fieldInfo : tableInfo.getFieldList()){
                BuildComment.createFieldComment(bw,fieldInfo.getComment());
                if(Constants.KNIFE4J_ENABLE){
                    bw.write("\t@Schema(description = \"" + fieldInfo.getComment() + "\")");
                    bw.newLine();
                }
                if(ArrayUtils.contains(Constants.IGNORE_BEAN_TOJSON_FIELDS,MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()))){
                    bw.write("\t" + Constants.IGNORE_BEAN_TOJSON_EXPRESSION);
                    bw.newLine();
                }
                if(ArrayUtils.contains(Constants.SQL_DATE_TIMES_TYPES,fieldInfo.getSqlType())){
                    bw.write("\t" + String.format(Constants.BEAN_DATE_FORMAT_EXPRESSION, DateUtils.YYYY_MM_DD_HH_MM_SS));
                    bw.newLine();
                    bw.write("\t" + String.format(Constants.BEAN_DATE_PARSE_EXPRESSION, DateUtils.YYYY_MM_DD_HH_MM_SS));
                    bw.newLine();
                }
                if(ArrayUtils.contains(Constants.SQL_DATE_TYPES,fieldInfo.getSqlType())){
                    bw.write("\t" + String.format(Constants.BEAN_DATE_FORMAT_EXPRESSION, DateUtils.YYYY_MM_DD));
                    bw.newLine();
                    bw.write("\t" + String.format(Constants.BEAN_DATE_PARSE_EXPRESSION, DateUtils.YYYY_MM_DD));
                    bw.newLine();
                }
                if(fieldEnumList.contains(fieldInfo)){
                    fieldInfo.setJavaType(MyStringUtils.upperCaseFirstLetter(fieldInfo.getPropertyName()) + "Enum");
                }
                bw.write("\tprivate " + fieldInfo.getJavaType() + " " + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + ";");
                bw.newLine();
            }
            bw.newLine();
            // getter and setter
            for(FieldInfo field : tableInfo.getFieldList()){
                String tempField = MyStringUtils.upperCaseFirstLetter(MyStringUtils.lowerCaseFirstLetter(field.getPropertyName()));
                bw.write("\tpublic void set" + tempField + "(" + field.getJavaType() + " " + MyStringUtils.lowerCaseFirstLetter(field.getPropertyName()) + ") {");
                bw.newLine();
                bw.write("\t\tthis."+MyStringUtils.lowerCaseFirstLetter(field.getPropertyName()) + " = " + MyStringUtils.lowerCaseFirstLetter(field.getPropertyName()) + ";");
                bw.newLine();
                bw.write("\t}");
                bw.newLine();
                bw.newLine();

                bw.write("\tpublic " + field.getJavaType() + " get" + tempField + "() {");
                bw.newLine();
                bw.write("\t\treturn " + MyStringUtils.lowerCaseFirstLetter(field.getPropertyName()) + ";");
                bw.newLine();
                bw.write("\t}");
                bw.newLine();
                bw.newLine();
            }

            // toString
//            @Override
//            public String toString() {
//                return "Category{" +
//                        "id=" + id +
//                        ", type=" + type +
//                        ", name='" + name + '\'' +
//                        ", sort=" + sort +
//                        ", createTime=" + DateUtils.format(createTime, DateTimePatternEnum.YYYY_MM_DD_HH_MM_SS.getPattern()) +
//                        ", updateTime=" + DateUtils.format(createTime, DateTimePatternEnum.YYYY_MM_DD_HH_MM_SS.getPattern()) +
//                        ", createUser=" + createUser +
//                        ", updateUser=" + updateUser +
//                        '}';
//            }
            bw.write("\t@Override");
            bw.newLine();
            bw.write("\tpublic String toString() {");
            bw.newLine();
            bw.write("\t\treturn " +  "\""  + tableInfo.getBeanName() +  "{\"" + " +");
            bw.newLine();
            List<FieldInfo> fieldInfoList = tableInfo.getFieldList();
            for(int i = 0;i < fieldInfoList.size();i++){
                FieldInfo field = fieldInfoList.get(i);
                if(i != 0){
                    bw.write("\t\t\t\", ");
                }else{
                    bw.write("\t\t\t\", ");
                }
                if("String".equals(field.getJavaType())){
                    bw.write(MyStringUtils.lowerCaseFirstLetter(field.getPropertyName()) +  "='\""  + " + " + MyStringUtils.lowerCaseFirstLetter(field.getPropertyName()) + " + " + "'\\''" + " +");
                } else if(ArrayUtils.contains(Constants.SQL_DATE_TIMES_TYPES,field.getSqlType())){
                    bw.write(MyStringUtils.lowerCaseFirstLetter(field.getPropertyName()) +  "='\""  + " + " + "(" + MyStringUtils.lowerCaseFirstLetter(field.getPropertyName()) + " == null ? " + " \"\" : " +
                            "DateUtils.format("+ MyStringUtils.lowerCaseFirstLetter(field.getPropertyName()) +", DateTimePatternEnum.YYYY_MM_DD_HH_MM_SS.getPattern())" + ") + " + "'\\''" + " +");
                } else if(ArrayUtils.contains(Constants.SQL_DATE_TYPES,field.getSqlType())){
                    bw.write(MyStringUtils.lowerCaseFirstLetter(field.getPropertyName()) +  "='\""  + " + " + "(" + MyStringUtils.lowerCaseFirstLetter(field.getPropertyName()) + " == null ? " + " \"\" : " +
                            "DateUtils.format("+ MyStringUtils.lowerCaseFirstLetter(field.getPropertyName()) +", DateTimePatternEnum.YYYY_MM_DD.getPattern())" + ") + " + "'\\''" + " +");
                } else{
                    bw.write(MyStringUtils.lowerCaseFirstLetter(field.getPropertyName()) +  "=\""  + " + " + MyStringUtils.lowerCaseFirstLetter(field.getPropertyName()) + " +");
                }
                bw.newLine();
            }
            bw.write("\t\t\t'}';");
            bw.newLine();
            bw.write("\t}");
            bw.newLine();


            bw.write("}");
            bw.flush();
        }catch (Exception e){
            logger.error("创建PO对象失败");
        }finally {
            if(bw != null){
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(outWriter != null){
                try {
                    outWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(out != null){
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
